#pragma once

#include "Enum.h"
#include <string>
#include <set>
#include <fstream>

struct NpcInfo {
	int dlevel, commonality;
	bool humanoid;
	int gender; // 0 none, 1 male only, 2 female only, 3 male/female
	int level, levelRange, stats[NUM_STATS], health;
	int corpseSatiation, corpseWeight;
	bool corpsePoisoned;
};

struct PlayerInfo {
	int stats[NUM_STATS], health;
};

struct AmmoInfo {
	int dlevel, commonality;
	int weight;
};

struct ArmorInfo {
	int dlevel, commonality;
	ArmorFamily family;
	int armor, dodge, weight;
};

struct FoodInfo {
	int dlevel, commonality;
	int satiation, weight;
};

struct IngredientInfo {
	int dlevel, commonality;
	IngredientFamily family;
	int weight;
};

struct MiscInfo {
	int dlevel, commonality;
	int weight;
};

struct PotionInfo {
	int dlevel, commonality;
	int weight;
};

struct ShieldInfo {
	int dlevel, commonality;
	int block, weight;
};

struct ToolInfo {
	int dlevel, commonality;
	int weight;
};

struct MeleeWeaponInfo {
	int dlevel, commonality;
	WeaponFamily family;
	int numDie, diceSides, attackBonus, accuracy, speed, weight;
	GripType grip;
};

struct RangedWeaponInfo {
	int dlevel, commonality;
	WeaponFamily family;
	int numDie, diceSides, attackBonus, accuracy, speed, weight, range, maxAmmo;
	AmmoType ammo;
	GripType grip;
};

struct MaterialInfo {
	int dlevel, commonality;
};

struct ScrollInfo {
	int dlevel, commonality;
	int weight;
};

struct ItemContainerInfo {
	int dlevel, commonality;
	int minItems, maxItems;
	bool lock, breakable;
};

struct ResourceInfo {
	int dlevel, commonality;
	ResourceFamily family;
	int health, quality;
	IngredientType ingredient;
	int bonusflag;
};

struct TrapInfo {
	int dlevel, commonality;
};

struct TalentInfo {
	std::set<Talent> prereqs;
	int stats[NUM_STATS];
	int gender; // 0 none, 1 male only, 2 female only, 3 male/female, 4 = any
};

class ObjectDatabase {
protected:
	NpcInfo m_npc[NUM_NPC_TYPES];
	PlayerInfo m_player[NUM_PLAYER_TYPES];
	AmmoInfo m_ammo[NUM_AMMO_TYPES];
	ArmorInfo m_armor[NUM_ARMOR_TYPES];
	FoodInfo m_food[NUM_FOOD_TYPES];
	IngredientInfo m_ingredient[NUM_INGREDIENT_TYPES];
	MiscInfo m_misc[NUM_MISC_TYPES];
	PotionInfo m_potion[NUM_POTION_TYPES];
	ShieldInfo m_shield[NUM_SHIELD_TYPES];
	ToolInfo m_tool[NUM_TOOL_TYPES];
	MeleeWeaponInfo m_meleeWeapon[NUM_MELEE_WEAPON_TYPES];
	RangedWeaponInfo m_rangedWeapon[NUM_RANGED_WEAPON_TYPES];
	MaterialInfo m_material[NUM_MATERIAL_TYPES];
	ScrollInfo m_scroll[NUM_SCROLL_TYPES];
	ItemContainerInfo m_itemcontainer[NUM_ITEMCONTAINER_TYPES];
	ResourceInfo m_resource[NUM_RESOURCE_TYPES];
	TrapInfo m_trap[NUM_TRAP_TYPES];
	PotionType m_potionNames[NUM_POTION_TYPES];
	ScrollType m_scrollNames[NUM_SCROLL_TYPES];
	TalentInfo m_talent[NUM_TALENTS];
	void initNpcInfo(NpcType type, int dlevel, int commonality, bool humanoid, int gender, int level, int levelRange, int str, int com, int nim, int lor, int per,
			int health, int satiation, int weight, bool poisoned, std::string name, std::string description);
	void initPlayerInfo(PlayerType type, int str, int com, int nim, int lor, int per, int health, std::string description);
	void initAmmoInfo(AmmoType type, int dlevel, int commonality, int weight, std::string name, std::string plural, std::string description);
	void initArmorInfo(ArmorType type, int dlevel, int commonality, ArmorFamily family, int armor, int dodge, int weight, std::string name, std::string description);
	void initFoodInfo(FoodType type, int dlevel, int commonality, int satiation, int weight, std::string name, std::string plural, std::string description);
	void initIngredientInfo(IngredientType type, int dlevel, int commonality, IngredientFamily family, int weight, std::string name, std::string plural, std::string description);
	void initMiscInfo(MiscType type, int dlevel, int commonality, int weight, bool identified, std::string name, std::string plural, std::string description);
	void initPotionInfo(PotionType type, int dlevel, int commonality, int weight, std::string name, std::string plural, std::string description, std::string scrambledName, std::string scrambledDescription, std::string scrambledPlural);
	void initShieldInfo(ShieldType type, int dlevel, int commonality, int block, int weight, std::string name, std::string description);
	void initToolInfo(ToolType type, int dlevel, int commonality, int weight, std::string name, std::string description);
	void initMeleeWeaponInfo(MeleeWeaponType type, int dlevel, int commonality, WeaponFamily family, int numDie, int diceSides, int attackBonus, int accuracy, int speed, int weight, GripType grip, std::string name, std::string description);
	void initRangedWeaponInfo(RangedWeaponType type, int dlevel, int commonality, WeaponFamily family, int numDie, int diceSides, int attackBonus, int accuracy, int speed, int weight, int range,
			int maxAmmo, GripType grip, AmmoType ammo, std::string name, std::string description);
	void initMaterialInfo(MaterialType type, int dlevel, int commonality, std::string name);
	void initScrollInfo(ScrollType type, int dlevel, int commonality, int weight, std::string name, std::string plural, std::string description, std::string scrambledName, std::string scrambledDescription, std::string scrambledPlural);
	void initItemContainerInfo(ItemContainerType type, int dlevel, int commonality, int minItems, int maxItems, bool lock, bool breakable, std::string name, std::string description);
	void initResourceInfo(ResourceType type, int dlevel, int commonality, ResourceFamily family, int health, int quality, IngredientType ingredient, int bonusflag, std::string name, std::string description);
	void initTrapInfo(TrapType type, int dlevel, int commonality, std::string name, std::string description);
	void initTalentInfo(Talent talent, int str, int com, int nim, int lor, int per, int gender, std::string name, std::string description, int numPrereqs, ...);
public:
	ObjectDatabase();
	~ObjectDatabase();
	const NpcInfo& getNpcInfo(NpcType type) const;
	const PlayerInfo& getPlayerInfo(PlayerType type) const;
	const AmmoInfo& getAmmoInfo(AmmoType type) const;
	const ArmorInfo& getArmorInfo(ArmorType type) const;
	const FoodInfo& getFoodInfo(FoodType type) const;
	const IngredientInfo& getIngredientInfo(IngredientType type) const;
	const MiscInfo& getMiscInfo(MiscType type) const;
	const PotionInfo& getPotionInfo(PotionType type) const;
	PotionType getScrambledPotionType(PotionType type) const;
	const ShieldInfo& getShieldInfo(ShieldType type) const;
	const ToolInfo& getToolInfo(ToolType type) const;
	const MeleeWeaponInfo& getMeleeWeaponInfo(MeleeWeaponType type) const;
	const RangedWeaponInfo& getRangedWeaponInfo(RangedWeaponType type) const;
	const MaterialInfo& getMaterialInfo(MaterialType type) const;
	const ScrollInfo& getScrollInfo(ScrollType type) const;
	ScrollType getScrambledScrollType(ScrollType type) const;
	const ItemContainerInfo& getItemContainerInfo(ItemContainerType type) const;
	const ResourceInfo& getResourceInfo(ResourceType type) const;
	const TrapInfo& getTrapInfo(TrapType type) const;
	const TalentInfo& getTalentInfo(Talent talent) const;
	void save(std::ofstream& file) const;
	void load(std::ifstream& file);
};

inline const NpcInfo& ObjectDatabase::getNpcInfo(NpcType type) const {return m_npc[type];}
inline const PlayerInfo& ObjectDatabase::getPlayerInfo(PlayerType type) const {return m_player[type];}
inline const AmmoInfo& ObjectDatabase::getAmmoInfo(AmmoType type) const {return m_ammo[type];}
inline const ArmorInfo& ObjectDatabase::getArmorInfo(ArmorType type) const {return m_armor[type];}
inline const FoodInfo& ObjectDatabase::getFoodInfo(FoodType type) const {return m_food[type];}
inline const IngredientInfo& ObjectDatabase::getIngredientInfo(IngredientType type) const {return m_ingredient[type];}
inline const MiscInfo& ObjectDatabase::getMiscInfo(MiscType type) const {return m_misc[type];}
inline const PotionInfo& ObjectDatabase::getPotionInfo(PotionType type) const {return m_potion[type];}
inline PotionType ObjectDatabase::getScrambledPotionType(PotionType type) const {return m_potionNames[type];}
inline const ShieldInfo& ObjectDatabase::getShieldInfo(ShieldType type) const {return m_shield[type];}
inline const ToolInfo& ObjectDatabase::getToolInfo(ToolType type) const {return m_tool[type];}
inline const MeleeWeaponInfo& ObjectDatabase::getMeleeWeaponInfo(MeleeWeaponType type) const {return m_meleeWeapon[type];}
inline const RangedWeaponInfo& ObjectDatabase::getRangedWeaponInfo(RangedWeaponType type) const {return m_rangedWeapon[type];}
inline const MaterialInfo& ObjectDatabase::getMaterialInfo(MaterialType type) const {return m_material[type];}
inline const ScrollInfo& ObjectDatabase::getScrollInfo(ScrollType type) const {return m_scroll[type];}
inline ScrollType ObjectDatabase::getScrambledScrollType(ScrollType type) const {return m_scrollNames[type];}
inline const ItemContainerInfo& ObjectDatabase::getItemContainerInfo(ItemContainerType type) const {return m_itemcontainer[type];}
inline const ResourceInfo& ObjectDatabase::getResourceInfo(ResourceType type) const {return m_resource[type];}
inline const TrapInfo& ObjectDatabase::getTrapInfo(TrapType type) const {return m_trap[type];}
inline const TalentInfo& ObjectDatabase::getTalentInfo(Talent talent) const {return m_talent[talent];}
